#include "app_buffer.h"
#include "log/log.h"
#include "stdlib.h"
#include "string.h"

//初始化一个子缓冲区（和缓冲区类似）
static SubBuffer * app_subBuffer_init(int total_size){
    SubBuffer *sub_buffer=(SubBuffer *)malloc(sizeof(SubBuffer));
    //这里按照规定的大小分配空间，并且用ptr指向空间的起点（数组[0]）
    sub_buffer->ptr=(unsigned char *)malloc(total_size);
    sub_buffer->total_size=total_size;
    sub_buffer->len=0;
    return sub_buffer;
}

//交换子缓冲区读写功能
static void app_subBuffer_swap(Buffer *buffer){
    log_debug("开始交换子缓冲区，加锁\n");
    //写锁是为了防止有线程还在写，加该锁会失败阻塞线程直到对方解锁
    pthread_mutex_lock(&buffer->write_lock);
    int temp=buffer->read_index;
    buffer->read_index=buffer->write_index;
    buffer->write_index=temp;
    log_debug("结束交换子缓冲区，解锁\n");
    pthread_mutex_unlock(&buffer->write_lock);
}

//初始化一个缓冲区
//参数：子缓冲区大小 返回值：缓冲区指针
Buffer * app_buffer_init(int total_size){
    //分配空间，注意数组是指针数组不是内存数组
    Buffer *buffer=(Buffer *)malloc(sizeof(Buffer));
    //初始化子缓冲区函数内部调用
    buffer->sub_buffers[0]=app_subBuffer_init(total_size);
    buffer->sub_buffers[1]=app_subBuffer_init(total_size);
    //0子缓存区为读缓存区，1子缓存区为写缓存区
    buffer->read_index=0; 
    buffer->write_index=1;

    //初始化读写锁（两个锁所以用初始化函数）
    pthread_mutex_init(&buffer->read_lock, NULL);
    pthread_mutex_init(&buffer->write_lock, NULL);

    return buffer;
}

//释放缓冲区
//参数：缓冲区指针
void app_buffer_free(Buffer *buffer){
    //从内向外释放
    free(buffer->sub_buffers[0]->ptr);
    free(buffer->sub_buffers[1]->ptr);
    free(buffer->sub_buffers[0]);
    free(buffer->sub_buffers[1]);
    //销毁锁
    pthread_mutex_destroy(&buffer->read_lock);
    pthread_mutex_destroy(&buffer->write_lock);
    free(buffer);
}

//向缓冲区写入数据
//参数：缓冲区指针 数据指针 数据长度 返回值：成功与否（0/-1）
int app_buffer_write(Buffer *buffer, unsigned char *data, int data_len){
    //data_len不能大于255，否则uchar类型会溢出
    if(data_len>255){
        log_error("一次写入数据长度不能大于255字节\n");
        return -1;
    }
    log_debug("开始写入数据，加锁\n");
    pthread_mutex_lock(&buffer->write_lock);
    //获取写缓存区(从参数里获取，根据写缓存索引和数组)
    SubBuffer *write_buffer=buffer->sub_buffers[buffer->write_index];
    //判断剩余空间是否足够
    if((write_buffer->total_size-write_buffer->len) < (data_len+1)){
        log_error("写缓存区剩余空间不足\n");
        pthread_mutex_unlock(&buffer->write_lock);
        return -1;
    }
    //先写入数据的长度(1字节表示)，方便调用
    //ptr指向缓存区开头+len表示缓存区数据下个元素
    write_buffer->ptr[write_buffer->len]=data_len;
    //再写入数据(写入位置：原点指针+len+1，写入长度：data_len)
    memcpy(write_buffer->ptr+write_buffer->len+1, data, data_len);
    //更新写缓存区长度
    write_buffer->len+=data_len+1;
    log_debug("结束写入数据，解锁\n");
    pthread_mutex_unlock(&buffer->write_lock);
    return 0;
}

//从缓冲区读取数据
//参数：缓冲区指针 数据指针 容器大小 返回值：数据长度
int app_buffer_read(Buffer *buffer, unsigned char *data, int data_buf_len){
    log_debug("开始读取数据，加锁\n");
    pthread_mutex_lock(&buffer->read_lock);
    //获取读缓存区(从参数里获取，根据读缓存索引和数组)
    SubBuffer *read_buffer=buffer->sub_buffers[buffer->read_index];
    //判断缓存区是否有数据,没有则交换缓存区
    if(read_buffer->len==0){
        app_subBuffer_swap(buffer);
        //重新获取读缓冲区
        read_buffer=buffer->sub_buffers[buffer->read_index];
        //判断交换后缓存区是否有数据
        if(read_buffer->len==0){
            log_error("缓冲区中没有数据\n");
            pthread_mutex_unlock(&buffer->read_lock);
            return -1;
        }
    }
    //获取数据长度(首1字节，缓存区拿数据一定拿那个最前面的）
    int data_len=read_buffer->ptr[0];
    //判断容器大小是否足够存下数据
    if(data_len>data_buf_len){
        log_error("容器大小不足\n");
        pthread_mutex_unlock(&buffer->read_lock);
        return -1;
    }
    //获取数据（从第二个字节开始，拿data_len个字节）//*.s表示打印data_len1个字符（解决无结束标记）
    memcpy(data, read_buffer->ptr+1, data_len);
    //将后面的数据往前移动，方便下次调用（移动长度：len-data_len-1，移动位置：原点指针+data_len+1）
    memmove(read_buffer->ptr, read_buffer->ptr+data_len+1, read_buffer->len-data_len-1);
    //更新读缓存区长度
    read_buffer->len-=data_len+1;
    log_debug("结束读取数据，解锁\n");
    pthread_mutex_unlock(&buffer->read_lock);
    return data_len;
}

